//
//  SideController.swift
//  XPSite
//
//  Created by zhuxietong on 2017/2/8.
//  Copyright © 2017年 zhuxietong. All rights reserved.
//

import UIKit
import JoLoading
import Eelay

public enum FloatSide {
    case left (width:CGFloat)
    case right (width:CGFloat)
    case bottom (height:CGFloat)
    case top (height:CGFloat)
    case none
    
    var width:CGFloat
    {
        get{
            switch self {
            case .left(width: let w),.right(width: let w):
                return w
            default:
                return Swidth
            }
        }
    }
    var height:CGFloat
    {
        get{
            switch self {
            case .bottom(height: let h),.top(height: let h):
                return h
            default:
                return Sheight
            }
        }
    }
}



public protocol GesSideRealization {
    func loadGesSideRealization()
    func gesSide()->FloatSide
    var gesObj:GesSideRealizationObj{get set}
}

extension GesSideRealization where Self:UIViewController{
 
    
    public func gesSide()->FloatSide{
        return .bottom(height: Swidth + 150.co)
    }
    
    public func loadGesSideRealization(){
        self.gesObj.controller = self
        self.gesObj.view = self.view
        self.gesObj.side = self.gesSide()
        view.backgroundColor = .clear
        gesObj.viewDidLoad()
    }
}

extension GesSideRealization where Self:LoadingPresenter{
    public var LoadingPresenterBg: UIView{
        get{
            return gesObj.contentView
        }
    }
}


open class GesSideRealizationObj: NSObject{
    
    weak var controller:UIViewController? = nil{
        didSet{
            controller?.modalPresentationStyle = .overFullScreen
        }
    }
    var view:UIView = UIView()
    public var side:FloatSide = .right(width: 260.co) {
        didSet{
            switch self.side {
            case .left(width: _):
                self.close_pt = [-Swidth,0]
            case .right(width: _):
                self.close_pt = [Swidth,0]
            case .bottom(height: _):
                self.close_pt = [0,Sheight]
            case .top(height: _):
                self.close_pt = [0,-Sheight]
            default:
                self.close_pt = [-(Swidth)-self.sideWidth,0]
            }
            
            switch self.side {
            case .left(width: _):
                self.open_pt = [-(Swidth)+self.sideWidth,0]
            case .right(width: _):
                self.open_pt = [(Swidth-self.sideWidth) ,0]
            case .top(height: _):
                self.open_pt = [0,-(Sheight)+self.sideHeight]
            case .bottom(height: _):
                self.open_pt = [0,(Sheight-self.sideHeight)]
            default:
                self.open_pt = [-(Swidth)+self.sideWidth,0]
            }
        }
    }
    
    open var sideWidth:CGFloat{
        return self.side.width
    }
    open var sideHeight:CGFloat{
        return self.side.height
    }
    
    let touchBt = UIButton()
    
    public var gestureAble = true
    public var strech_distance:Int{
        switch self.side {
        case .left,.right:
            return Int(Swidth - self.sideWidth)
        default:
            return Int(Sheight - self.sideHeight)
        }
        
    }
    
//    override open var LoadingPresenterBg: UIView{
//        get{
//            return contentView
//        }
//    }
    public var floatBack = UIControl()
    
    open var contentView:UIView{
        return _contentView
    }
    
    
    open var backgroundView:UIView{
        let view = UIView()
        view.backgroundColor = .clear
        return view
    }
    
    var __backgroundView:UIView? = nil
    
    
    public required override init() {
        super.init()
    }
    
    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    open lazy var _contentView: UIView = { [unowned self] in
        let views = self.view.subviews.filter {$0.tag == 880611}
        if views.count != 0 {
            return views.first!.subviews[0]
        }
        let cview = UIView()
        self.view.eelay = [
            [self.touchBt,[ee.T.L.B.R]],
        ]
        self.touchBt.addTarget(self, action: #selector(close), for: .touchUpInside)
        
        if self.__backgroundView == nil{
            self.__backgroundView = self.backgroundView
        }
        self.floatBack.eelay = [
            [self.__backgroundView!,[ee.T.L.B.R]],
        ]
        
        
        
        switch self.side {
        case .right:
            self.view.eelay = [
                [self.floatBack,Int(Swidth),[ee.R,self.strech_distance],[ee.T.B]],
            ]
            self.floatBack.eelay = [
                [cview,[ee.T.L.B,[0,0,0]],Int(self.sideWidth).+1000],
            ]
        case .left:
            let lf = -(Swidth - self.sideWidth)
            self.view.eelay = [
                [self.floatBack,Int(Swidth),[ee.L,Int(lf)],[ee.T.B]],
            ]
            self.floatBack.eelay = [
                [cview,[ee.T.R.B,[0,0,0]],Int(self.sideWidth).+1000],
            ]
        case .bottom:
            self.view.eelay = [
                [self.floatBack,"\(Sheight)",[ee.B,self.strech_distance],[ee.L.R]],
            ]
            self.floatBack.eelay = [
                [cview,[ee.L.T.R,[0,0,0]],"\(self.sideHeight)".+1000],
            ]
        case .top:
            let lf = -(Sheight - self.sideHeight)
            self.view.eelay = [
                [self.floatBack,"\(Sheight)",[ee.T,Int(lf)],[ee.L.R]],
            ]
            self.floatBack.eelay = [
                [cview,[ee.L.B.R,[0,0,0]],"\(self.sideHeight)".+1000],
            ]
        default:
            break
        }
        
        self.floatBack.tag = 880611
        return cview
        }()
    
    
    
    open func viewDidLoad() {
        
        view.backgroundColor = .clear
        floatBack.backgroundColor = .clear
        contentView.backgroundColor = .clear
        touchBt.backgroundColor = .color(light: "#00000054", dark: "#3335")
        
        
        self.contentView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(onPanGuesture)))
        self.touchBt.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(onPanGuesture)))
        switch self.side {
        case .right:
            floatBack.frame.origin.x = Swidth
        case .left:
            floatBack.frame.origin.x = -(Swidth)
        case .bottom:
            floatBack.frame.origin.y = Sheight
        case .top:
            floatBack.frame.origin.y = -(Sheight)
        default:
            floatBack.frame.origin.x = Swidth
        }
        
        switch self.side {
        case .left,.right,.none:
            self.floatBack.frame.origin.x = self.close_pt.x
        default:
            self.floatBack.frame.origin.y = self.close_pt.y
        }
        
        self.floatBack.alpha = 0.0
        touchBt.layer.opacity = 0.0
        
    }
 
    
//    open override func viewDidAppear(_ animated: Bool) {
//        super.viewDidAppear(animated)
//        open()
//    }
    
    open var close_pt:CGPoint = CGPoint.zero

    open var open_pt:CGPoint = CGPoint.zero
        
    
    
    public var last_pan_point:CGPoint = [0,0]
    
    
    
    
    
}

extension GesSideRealizationObj{

    
    @objc open func onPanGuesture(sender:UIPanGestureRecognizer) {
        if !gestureAble{
            return
        }
        
        guard let coview = (controller as? LoadingPresenter)?.jo_contentView else {
            return
        }
        let translation = sender.translation(in: coview)
        
        switch self.side {
        case .left(width: _):
            switch sender.state {
            case .began,.changed:
                if sender.state == .began{
                    last_pan_point = [0,0]
                }
                if translation.x < 0
                {
                    self.floatBack.frame.origin.x   = open_pt.x + translation.x
                }
                else{
                    var s = (sideWidth - translation.x)/sideWidth
                    if s < 0 {s = 0}
                    s = s * s
                    let trans_x = open_pt.x + translation.x*s
                    if self.floatBack.frame.origin.x < trans_x{
                        self.floatBack.frame.origin.x =  trans_x
                        last_pan_point = translation
                    }
                    else{
                        if  last_pan_point.x > translation.x{
                            self.floatBack.frame.origin.x =  trans_x
                        }
                    }
                }
            case .ended:
                if floatBack.frame.origin.x > open_pt.x
                {
                    self.gotoOpen()
                }else
                {
                    self.close()
                }
                
            default: break
                
            }
        case .top(height: _):
            switch sender.state {
            case .began,.changed:
                if sender.state == .began{
                    last_pan_point = [0,0]
                }
                if translation.y < 0
                {
                    self.floatBack.frame.origin.y   = open_pt.y + translation.y
                }
                else{
                    var s = (sideHeight - translation.y)/sideHeight
                    if s < 0 {s = 0}
                    s = s * s
                    let trans_y = open_pt.y + translation.y*s
                    
                    if (self.floatBack.frame.origin.y < trans_y){
                        self.floatBack.frame.origin.y =  trans_y
                        last_pan_point = translation
                    }
                    else{
                        if  last_pan_point.y > translation.y{
                            self.floatBack.frame.origin.y =  trans_y
                        }
                    }
                }
            case .ended:
                if floatBack.frame.origin.y > open_pt.y
                {
                    self.gotoOpen()
                }else
                {
                    self.close()
                }
                
            default: break
                
            }
        case .right(width: _):
            switch sender.state {
            case .began,.changed:
                if sender.state == .began{
                    last_pan_point = [0,0]
                }
                if translation.x > 0
                {
                    self.floatBack.frame.origin.x   = open_pt.x + translation.x
                }
                else{
                    var s = (sideWidth+translation.x)/sideWidth
                    if s < 0 {s = 0}
                    s = s * s
                    let trans_x = open_pt.x + translation.x*s
                    if self.floatBack.frame.origin.x > trans_x{
                        self.floatBack.frame.origin.x =  trans_x
                        last_pan_point = translation
                    }
                    else{
                        if  last_pan_point.x < translation.x{
                            self.floatBack.frame.origin.x =  trans_x
                        }
                    }
                }
            case .ended:
                if floatBack.frame.origin.x < open_pt.x
                {
                    self.gotoOpen()
                }else
                {
                    self.close()
                }
            default: break
            }
        case .bottom(height: _):
            switch sender.state {
            case .began,.changed:
                if sender.state == .began{
                    last_pan_point = [0,0]
                }
                if translation.y > 0
                {
                    self.floatBack.frame.origin.y   = open_pt.y + translation.y
                }
                else{
                    var s = (sideHeight+translation.y)/sideHeight
                    if s < 0 {s = 0}
                    
                    s = s * s
                    let trans_y = open_pt.y + translation.y*s
                    if self.floatBack.frame.origin.y > trans_y{
                        self.floatBack.frame.origin.y =  trans_y
                        last_pan_point = translation
                    }
                    else{
                        if  last_pan_point.y < translation.y{
                            self.floatBack.frame.origin.y =  trans_y
                        }
                    }
                }
            case .ended:
                if floatBack.frame.origin.y < open_pt.y
                {
                    self.gotoOpen()
                }else
                {
                    self.close()
                }
            default: break
        }
            
        default:
            break
        }
    }
    
    
    @objc open func close() {
        
        print("--|PPP|\(#function)=\(#line)")

//        touchBt.layer.opacity = 1.0
        weak var wself = self
                
//        self.floatBack.alpha = 1.0
        //        touchBt.layer.opacity = 0.0
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDuration(0.1)
        UIView.setAnimationCurve(UIView.AnimationCurve.init(rawValue: 7)!)
        switch self.side {
        case .left,.right:
            self.floatBack.frame.origin.x = self.close_pt.x
        default:
            self.floatBack.frame.origin.y = self.close_pt.y
        }
        touchBt.layer.opacity = 0
        UIView.commitAnimations()
        co_delay(delay: 0.1) {
            wself?.controller?.dismiss(animated: false, completion: nil)
        }
        

//        UIView.animate(withDuration: 0.2, animations: {
//            guard let ws = wself else{
//                return
//            }
//            ws.touchBt.layer.opacity = 0.0
//            switch ws.side {
//            case .left,.right:
//                ws.floatBack.frame.origin.x = ws.close_pt.x
//            default:
//                ws.floatBack.frame.origin.y = ws.close_pt.y
//            }
//        }, completion: { finish in
//            guard let ws = wself else{
//                return
//            }
//            ws.touchBt.layer.opacity = 0.0
//            switch ws.side {
//            case .left,.right:
//                ws.floatBack.frame.origin.x = ws.close_pt.x
//            default:
//                ws.floatBack.frame.origin.y = ws.close_pt.y
//            }
//
//            wself?.dismiss(animated: false, completion: nil)
//        })
        
    }
    
    
    open func gotoOpen() {
//        print("--|PPP|\(#function)=\(#line)")
        
        self.floatBack.alpha = 1.0
        //        touchBt.layer.opacity = 0.0
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDuration(0.1)
        UIView.setAnimationCurve(UIView.AnimationCurve.init(rawValue: 7)!)
        switch self.side {
        case .left,.right:
            self.floatBack.frame.origin.x = self.open_pt.x
        default:
            self.floatBack.frame.origin.y = self.open_pt.y
        }
        touchBt.layer.opacity = 1.0
        UIView.commitAnimations()
        
    }
    
    open func open() {
//        print("--|PPP|\(#function)=\(#line)")

        switch self.side {
        case .left,.right:
            self.floatBack.frame.origin.x = self.close_pt.x
        default:
            self.floatBack.frame.origin.y = self.close_pt.y
        }
        self.floatBack.alpha = 1.0
        touchBt.layer.opacity = 0.0
        
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDuration(0.25)
        UIView.setAnimationCurve(UIView.AnimationCurve.init(rawValue: 7)!)
        switch self.side {
        case .left,.right:
            self.floatBack.frame.origin.x = self.open_pt.x
        default:
            self.floatBack.frame.origin.y = self.open_pt.y
        }
        touchBt.layer.opacity = 1.0
        UIView.commitAnimations()
        
    }
}

